package com.bianmaba.spring.security.basic.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.*;

import static com.bianmaba.spring.security.autoconfig.WebSecurityAutoConfiguration.ORDER;


@Configuration
@ConditionalOnClass({WebSecurityConfigurerAdapter.class})
//如果此类加载前已经存在指定类型的实例，则此类将不会被实例化(如果有继承关系，则可能会执行构造函数，但实际为同一个实例时为正常，否则可能不正常)
@ConditionalOnMissingBean({BasicWebSecurityConfiguration.class})
@ConditionalOnWebApplication(
        type = ConditionalOnWebApplication.Type.SERVLET
)
@EnableWebSecurity
//配置初始化排序，此值越低，越靠前，但@Import引入的类此注解无效
@Order(ORDER)
public class BasicWebSecurityConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(BasicWebSecurityConfiguration.class);

    public BasicWebSecurityConfiguration() {
        if (this.getClass().getName().equals(BasicWebSecurityConfiguration.class.getName())) ;
        {
            LOG.info("加载WEB安全性配置(order=" + ORDER + "):" + this.getClass().getName());
        }
    }


    /**
     * 重写用户服务类
     * <pre>
     *     将会禁止系统的{@link org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration}自动配置
     * </pre>
     */
    @Configuration
//如果此类加载前已经存在实例，则此类将不会被实例化
    @ConditionalOnMissingBean({UserDetailsService.class})
    @Order(ORDER)//配置初始化排序，此值越低，越靠前，但@Import引入的类此注解无效
    public static class BasicUserDetailsService implements UserDetailsService {

        public BasicUserDetailsService() {
            if (this.getClass().getName().equals(BasicUserDetailsService.class.getName())) ;
            {
                LOG.info("加载自动化配置(order=" + ORDER + "):" + this.getClass().getName());
            }
        }

        @Autowired
        private SecurityPropertiesConfiguration.WebSecurityProperties basicSecurityProperties;

        /**
         * 根据用户输入的用户名，找到相应用户，如果没找到则抛出UsernameNotFoundException异常
         *
         * @param username 用户登录输入的用户名
         * @return 用户信息
         * @throws UsernameNotFoundException 用户不存在的异常
         */
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            List<Map<String, String>> users = basicSecurityProperties.getUsers();
            Map<String, String> user = findUser(users, username);
            if (user != null) {
                //解析角色配置
                List<GrantedAuthority> grantedAuthorities = createGrantedAuthorities(user.get("roles"));
                UserDetails userDetails = new User(user.get("username"), user.get("password"), grantedAuthorities);
                return userDetails;
            }
            throw new UsernameNotFoundException("用户名在系统中不存在，请确认用户名是否正确！");
        }

        /**
         * 将用户配置的用户角色信息解析为角色列表，并在角色名前添加ROLE_
         *
         * @param rolesStr 用户配置文件中配置的角色信息spring.security.user.roles或spring.security.users[x].roles
         * @return 返回用户的拥有的权限
         */
        private List<GrantedAuthority> createGrantedAuthorities(String rolesStr) {
            List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(0);
            if (rolesStr != null) {
                String[] roles = rolesStr.split("[,]");
                for (String role : roles) {
                    role = role.trim();
                    if (role.length() > 0) {
                        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role.trim()));
                    }
                }
            }
            return grantedAuthorities;
        }

        //用户配置的用户中查找指定用户名的用户（包含spring.security.user及spring.security.users中的用户）
        private Map<String, String> findUser(List<Map<String, String>> users, String username) {
            for (Map<String, String> user : users) {
                if (user.get("username").equals(username)) {
                    return user;
                }
            }
            return null;
        }
    }
}
